package org.charles.zhifou.common.exception;

import lombok.extern.slf4j.Slf4j;
import org.charles.zhifou.common.response.BaseResponse;
import org.charles.zhifou.common.response.ResponseCodeEnum;
import org.charles.zhifou.common.response.ResponseUtils;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.HandlerMethodValidationException;

import java.util.Arrays;
import java.util.List;

/**
 * <h1>全局异常处理器</h1>
 *
 * @author charles
 * @version 1.0
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 请求体异常
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public BaseResponse<?> exceptionHandler(HttpMessageNotReadableException e) {
        String message = e.getMessage().replace("JSON parse error: ", "");
        return ResponseUtils.error(ResponseCodeEnum.PARAMS_ERROR, message);
    }

    // <1> 处理 form data方式调用接口校验失败抛出的异常

    // @ExceptionHandler(BindException.class)
    // public BaseResponse<?> bindExceptionHandler(BindException e) {
    //     List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
    //     List<String> errorMessages = fieldErrors.stream()
    //             .map(DefaultMessageSourceResolvable::getDefaultMessage)
    //             .toList();
    //     return ResponseUtils.error(ResponseCodeEnum.PARAMS_ERROR, errorMessages.toString());
    // }

    /**
     * SpringBoot Validation: 处理 JSON 请求体调用接口校验失败抛出的异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public BaseResponse<?> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        List<String> errorMessages = fieldErrors.stream()
                .map(DefaultMessageSourceResolvable::getDefaultMessage)
                .toList();
        return ResponseUtils.error(ResponseCodeEnum.PARAMS_ERROR, String.join(", ", errorMessages));
    }

    // <3> 处理单个参数校验失败抛出的异常
    // @ExceptionHandler(ConstraintViolationException.class)
    // public BaseResponse<?> constraintViolationExceptionHandler(ConstraintViolationException e) {
    //     Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
    //     List<String> errorMessages = constraintViolations.stream()
    //             .map(ConstraintViolation::getMessage)
    //             .toList();
    //     return ResponseUtils.error(ResponseCodeEnum.PARAMS_ERROR, errorMessages.toString());
    // }

    /**
     * SpringBoot Validation: 处理直接写在 Controller 形参上的异常
     */
    @ExceptionHandler(HandlerMethodValidationException.class)
    public BaseResponse<?> validationHandler(HandlerMethodValidationException e) {
        Object[] detailMessageArguments = e.getDetailMessageArguments();
        List<String> errorMessages = null;
        if (detailMessageArguments != null) {
            errorMessages = Arrays.stream(detailMessageArguments)
                    .map(Object::toString)
                    .map(str -> "\"" + str + "\"")
                    .toList();
        }
        return ResponseUtils.error(ResponseCodeEnum.PARAMS_ERROR, errorMessages == null ? "" : errorMessages.toString());
    }

    /**
     * 用于在代码中用 ThrowUtils.throwIf() 抛出的异常的捕捉和返回
     * @param e
     * @return
     */
    @ExceptionHandler(BusinessException.class)
    public BaseResponse<?> businessExceptionHandler(BusinessException e) {
        log.error("业务逻辑错误: {}", e);
        return new BaseResponse<>(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(RuntimeException.class)
    public BaseResponse<?> runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        return ResponseUtils.error(ResponseCodeEnum.SYSTEM_ERROR, "系统错误");
    }
}
